/*! \file
 * \brief Enter a brief description here.
 *
 * Enter a detailed description here. (optional)
 * \author Author (Ivo Wingelaar)
 * \date Date (2011)
 * \version Version (0.0.1)
 * \copyright Copyright (GNU LGPL v3)
 */

#ifndef __LYNX_GLSL_MATERIAL_RENDERER_HPP_INCLUDED__
#define __LYNX_GLSL_MATERIAL_RENDERER_HPP_INCLUDED__

#include "LynxConfig.hpp"

#define GL_GLEXT_LEGACY 1

#ifdef _LYNX_WINDOWS_
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif // _LYNX_WINDOWS_

#include <GL/gl.h>
#include <GL/glext.h>

#include "LynxMaterialRenderer.hpp"
#include "LynxMaterialRendererServices.hpp"
#include "LynxGPUProgrammingServices.hpp"

namespace Lynx
{

class VideoManager_C;
class ShaderConstantSetCallBack;

//! Class for using GLSL shaders with OpenGL
//! Please note: This renderer implements its own IMaterialRendererServices
class GLSLMaterialRenderer : public MaterialRenderer, public MaterialRendererServices
{
public:
    //! Constructor
    GLSLMaterialRenderer(
        VideoManager_C* driver,
        int32_t& outMaterialTypeNr,
        const char* vertexShaderProgram = 0,
        const char* vertexShaderEntryPointName = 0,
        E_VERTEX_SHADER_TYPE vsCompileTarget = EVST_VS_1_1,
        const char* pixelShaderProgram = 0,
        const char* pixelShaderEntryPointName = 0,
        E_PIXEL_SHADER_TYPE psCompileTarget = EPST_PS_1_1,
        const char* geometryShaderProgram = 0,
        const char* geometryShaderEntryPointName = "main",
        E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0,
        E_PRIMITIVE_TYPE inType = EPT_TRIANGLES,
        E_PRIMITIVE_TYPE outType = EPT_TRIANGLE_STRIP,
        uint32_t verticesOut = 0,
        ShaderConstantSetCallBack* callback = 0,
        MaterialRenderer* baseMaterial = 0,
        int32_t userData = 0);

    //! Destructor
    virtual ~GLSLMaterialRenderer();

    virtual void on_set_material(const Material& material, const Material& lastMaterial,
                               bool resetAllRenderstates, MaterialRendererServices* services);

    virtual bool on_render(MaterialRendererServices* service, E_VERTEX_TYPE vtxtype);

    virtual void on_unset_material();

    //! Returns if the material is transparent.
    virtual bool is_transparent() const;

    // implementations for the render services
    virtual void set_basic_render_states(const Material& material, const Material& lastMaterial, bool resetAllRenderstates);
    virtual bool set_vertex_shader_constant(const char* name, const float* floats, int count);
    virtual void set_vertex_shader_constant(const float* data, int32_t startRegister, int32_t constantAmount=1);
    virtual bool set_pixel_shader_constant(const char* name, const float* floats, int count);
    virtual void set_pixel_shader_constant(const float* data, int32_t startRegister, int32_t constantAmount=1);
    virtual VideoManager* get_video_manager();

protected:

    //! constructor only for use by derived classes who want to
    //! create a fall back material for example.
    GLSLMaterialRenderer(VideoManager_C* driver,
                         ShaderConstantSetCallBack* callback,
                         MaterialRenderer* baseMaterial,
                         int32_t userData=0);

    void init(int32_t& outMaterialTypeNr,
              const char* vertexShaderProgram,
              const char* pixelShaderProgram,
              const char* geometryShaderProgram,
              E_PRIMITIVE_TYPE inType=EPT_TRIANGLES,
              E_PRIMITIVE_TYPE outType=EPT_TRIANGLE_STRIP,
              uint32_t verticesOut=0);

    bool createProgram();
    bool createShader(GLenum shaderType, const char* shader);
    bool linkProgram();

    VideoManager_C* mDriver;
    ShaderConstantSetCallBack* mCallBack;
    MaterialRenderer* mBaseMaterial;

    struct UniformInfo
    {
        std::string name;
        GLenum type;
    };

    GLhandleARB mProgram;
    std::vector<UniformInfo> mUniformInfo;
    int32_t mUserData;
};

} // namespace Lynx

#endif // __LYNX_GLSL_MATERIAL_RENDERER_HPP_INCLUDED__

